home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 10 - 1994 / 10.12 Dec 94 / ThreadedSprocket / Lib / AEThreads.c next >
Encoding:
Text File  |  1994-10-17  |  5.4 KB  |  235 lines  |  [TEXT/MPS ]

  1. //    AEThreads.h
  2. //
  3. //    Copyright © 1993-94 Steve Sisak
  4. //    
  5. //    License is granted to use, modify, make derivative works, and 
  6. //    duplicate this code at will, so long as this notice remains intact.
  7. //
  8.  
  9. #ifndef __AETHREADS__
  10. #include "AEThreads.h"
  11. #endif
  12. #ifndef __ERRORS__
  13. #include <Errors.h>
  14. #endif
  15. #ifndef __APPLEEVENTS__
  16. #include <AppleEvents.h>
  17. #endif
  18. #if __MWERKS__
  19. #if defined(powerc) || defined(__powerc)
  20. #include <CPlusLibPPC.h>
  21. #else
  22. #include <stdlib.h>
  23. #include <CPlusLib68k.h>
  24. #endif
  25. #endif
  26.  
  27. typedef struct AEThreadDesc  AEThreadDesc;
  28. typedef struct AEThreadParam AEThreadParam;
  29. typedef struct AESwapData    AESwapData;
  30.  
  31. struct AEThreadDesc                    // Kept in the OS refcon
  32. {
  33.     AEEventHandlerUPP    handler;    // The real handler
  34.     long                refcon;        // The real refcon
  35.     Size                stackSize;    // Stack size for handling event
  36.     ThreadOptions        options;    // Thread options for event
  37.     ThreadID            holder;        // used as a semaphore
  38. };
  39.  
  40. struct AEThreadParam                // Used in spawning
  41. {
  42.     const AppleEvent*    event;
  43.     AppleEvent*            reply;
  44.     AEThreadDesc*        desc;
  45.     ThreadID            thread;
  46.     OSErr                result;
  47. };
  48.  
  49. struct AESwapData
  50. {
  51.     void*                fTopHandler;    // Top failure handler
  52.  
  53. #ifdef __MWERKS__
  54.     DestructorChain*    fStaticChain;    //
  55. #endif
  56. };
  57.  
  58. pascal void        SwitchInHandler(ThreadID threadBeingSwitched, void *switchProcParam);
  59. pascal void        SwitchOutHandler(ThreadID threadBeingSwitched, void *switchProcParam);
  60. pascal OSErr    SpawnAEThread(const AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon);
  61. pascal long        AEThread(AEThreadParam* parms);
  62.  
  63. AEEventHandlerUPP gSpawnAEThreadUPP = nil;
  64.  
  65. #pragma segment foobar
  66.  
  67. pascal OSErr AEInstallThreadedEventHandler(
  68.     AEEventClass        theAEEventClass,
  69.     AEEventID            theAEEventID,
  70.     AEEventHandlerUPP    proc,
  71.     long                handlerRefcon,
  72.     ThreadOptions        options,
  73.     Size                stacksize)
  74. {
  75.     AEThreadDesc* desc = (AEThreadDesc*) NewPtr(sizeof(AEThreadDesc));
  76.     OSErr          err  = MemError();
  77.     
  78.     if (gSpawnAEThreadUPP == nil)
  79.     {
  80.         gSpawnAEThreadUPP = NewAEEventHandlerProc(SpawnAEThread);
  81.     }
  82.     
  83.     if (err == noErr)
  84.     {
  85.         desc->handler    = proc;
  86.         desc->refcon    = handlerRefcon;
  87.         desc->stackSize    = stacksize;
  88.         desc->options    = options;
  89.         desc->holder    = kNoThreadID;
  90.  
  91.         err = AEInstallEventHandler(theAEEventClass, theAEEventID, gSpawnAEThreadUPP, (long) desc, false);
  92.     }
  93.     
  94.     return err;
  95. }
  96.  
  97. #pragma segment AEThread
  98.  
  99. pascal void SwitchInHandler(ThreadID threadBeingSwitched, void *switchProcParam)
  100. {
  101.     AESwapData* swap = (AESwapData*) switchProcParam;
  102.  
  103. #ifdef __MWERKS__
  104.     swap->fStaticChain = __local_destructor_chain;
  105. #endif
  106. }
  107.  
  108. pascal void SwitchOutHandler(ThreadID threadBeingSwitched, void *switchProcParam)
  109. {
  110.     AESwapData* swap = (AESwapData*) switchProcParam;
  111.  
  112. #ifdef __MWERKS__
  113.     __local_destructor_chain = swap->fStaticChain;
  114. #endif
  115. }
  116.  
  117.  
  118. #define ErrCheck(label, result)  if ((result) != noErr) goto label;
  119.  
  120. pascal long AEThread(AEThreadParam* parms)
  121. {
  122.     AppleEvent        event;            // Original parameters we care about
  123.     AppleEvent        reply;
  124.     AEThreadDesc*    desc;
  125.     OSErr            err;
  126.     OSErr            procErr;
  127.     AESwapData        swap;
  128.  
  129.     event = *parms->event;            // copy these into our own stack frame
  130.     reply = *parms->reply;
  131.     desc  =  parms->desc;
  132.  
  133. #if 0    
  134.     myTopHandler = gTopHandler;        // Save global failure handler
  135.     gTopHandler  = nil;                // don't let failures propagate outside
  136. #endif
  137.  
  138.     ErrCheck(punt, err = SetThreadSwitcher(kCurrentThreadID, SwitchInHandler,  &swap, true));
  139.     ErrCheck(punt, err = SetThreadSwitcher(kCurrentThreadID, SwitchOutHandler, &swap, false));
  140.     ErrCheck(punt, err = AESuspendTheCurrentEvent(&event));
  141.  
  142.     parms->result = noErr;        // Let caller know we're ready
  143.  
  144.     // At this point, we need to let our caller return
  145.  
  146.     while (desc->holder != kNoThreadID)
  147.     {
  148.         YieldToThread(desc->holder);
  149.     }
  150.  
  151.     // We are now on our own
  152.     
  153.     procErr = err = CallAEEventHandlerProc(desc->handler, &event, &reply, desc->refcon);
  154.  
  155.         // Since the event was suspended, we need to stuff the error code ourselves    
  156.         // note that there's not much we can do about reporting errors beyond here
  157.         
  158.     err = AEPutAttributePtr(&reply, keyErrorNumber, typeShortInteger, &procErr, sizeof(procErr));
  159.  
  160. #if qDebug
  161.     if (err)
  162.         ProgramBreak("\pAEPutAttributePtr failed installing error code - very bad");
  163. #endif
  164.  
  165.     err = AEResumeTheCurrentEvent(&event, &reply, kAENoDispatch, 0);    // This had better work
  166.  
  167. #if qDebug
  168.     if (err)
  169.         DebugStr("\pAEResumeTheCurrentEvent failed - very bad");
  170. #endif
  171.  
  172. #if 0
  173.     gTopHandler     = myTopHandler;    // Restore global failure handler
  174.     myTopHandler = nil;                // Keep terminator from firing handlers
  175. #endif
  176.  
  177. punt:
  178.     parms->result = err;
  179.     return nil;
  180. }
  181.  
  182. #pragma segment Spawn
  183.  
  184. pascal OSErr SpawnAEThread(const AppleEvent *event, AppleEvent *reply, long handlerRefcon)
  185. {
  186.     AEThreadParam param;
  187.     
  188.     param.event  = event;
  189.     param.reply  = reply;
  190.     param.desc     = (AEThreadDesc*) handlerRefcon;
  191.     param.thread = kNoThreadID;
  192.  
  193.     if (!param.desc)
  194.     {
  195.         param.result = paramErr;
  196.     }
  197.     else
  198.     {
  199.         while (param.desc->holder != kNoThreadID)    // make sure no-one else is trying to start a handler
  200.         {
  201.             YieldToAnyThread();
  202.         }
  203.         
  204.         if ((param.result = GetCurrentThread(¶m.desc->holder)) == noErr)    // Grab the semaphore
  205.         {
  206.             param.result = NewThread(kCooperativeThread,
  207.                             (ThreadEntryProcPtr) &AEThread,
  208.                             ¶m,
  209.                             param.desc->stackSize,
  210.                             param.desc->options,
  211.                             nil,
  212.                             ¶m.thread);
  213.             
  214.             if (param.result == noErr)
  215.             {
  216.                 param.result = 1;
  217.             
  218.                 do
  219.                 {
  220.                     YieldToThread(param.thread);
  221.                 }
  222.                 while (param.result == 1);    // Wait for thread to pick up parameters
  223.             }
  224.         }
  225.         
  226.         param.desc->holder = kNoThreadID;    // release any claims we have
  227.     }
  228.     
  229.     return param.result;
  230. }
  231.  
  232.  
  233.  
  234.  
  235.